#include "river.h"

#define WIDTH 1024
#define HEIGHT 768

#define START_X 0
#define START_Y 5
#define LIMIT_X 300
#define LIMIT_Y HEIGHT - 200
#define DIST_RX 770

#define BARCO_VEL_X 6

#define IMG_WIDTH  45
#define IMG_HEIGHT 45

#define NUM_X ((LIMIT_X - START_X) / IMG_WIDTH)
#define NUM_Y ((LIMIT_Y - START_Y) / IMG_HEIGHT)

#define COR_STR makecol(255, 100, 200)

#define BARCO_EX  280
#define BARCO_DX  550
#define BARCO_Y   300

/* Todas threads devem manter sua informacao aqui  
   REGRAS:
     * thread i soh pode alterar posicao i do vetor;
*/
int thrd_len, thrd_margem[5];
float tempo;
pthread_mutex_t mutex_margem;
t_status thrd_status[4*N];
t_image imagens;
t_barco barco;
BITMAP *buffer;

/* Inicializa a margem sem nenhuma thread */
void init_margem()
{
   thrd_margem[0]=-1;
   thrd_margem[1]=-1;
   thrd_margem[2]=-1;
   thrd_margem[3]=-1;
   thrd_margem[4]=-1;
}

void margem_add_thrd(int id)
{
   short int i;
   pthread_mutex_lock(&mutex_margem);
   for(i=0; i<5; i++)
   {
      if(thrd_margem[i]==-1)
      {
         thrd_margem[i]=id;
         thrd_status[id].x=BARCO_EX-10;
         thrd_status[id].y=BARCO_Y-40+45*i;
         break;
      }
   }
   pthread_mutex_unlock(&mutex_margem);
}

void margem_del_thrd(int id)
{
   short int i;
   for(i=0; i<5; i++)
   {
      if(thrd_margem[i]==id)
      {
         thrd_margem[i]=-1;
         break;
      }
   }
}
     

void init_video()
{
   /* INICIO DA INICIALIZACAO DO ALLEGRO */

   allegro_init();
   set_config_file("river.cfg");
   install_timer();
   install_keyboard();
   set_color_depth(32); 
   if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, WIDTH, HEIGHT, 0, 0))
   {
        printf("Video Error: %s", allegro_error);
        exit(1);
   }
   set_color_conversion(COLORCONV_NONE);
   buffer = create_bitmap(WIDTH, HEIGHT);

   /* FIM DA INICIALIZACAO DO ALLEGRO */
}

void barco_reset()
{
   int i;
   for (i=0; i<4; barco.tripulacao[i++]=-1);
}

void barco_desembarcar()
{
   int i, id;
   for(i=0; i<4;i++)
      if ((id = barco.tripulacao[i]) != -1)
      {
         thrd_status[id].y = (id / NUM_X)*IMG_HEIGHT + START_Y;
         thrd_status[id].x = (id % NUM_X)*IMG_WIDTH + DIST_RX;
         margem_del_thrd(id);
      }

   barco_reset();
   barco_zarpar();
}

void barco_embarcar()
{
  /* Informacao para modo debug */
  d_printf("Barco pronto\n");
  /* Informa as threads que o barco chegou a margem e existem 4 vagas */
  sem_post(&barco_pronto);
  sem_post(&barco_pronto);
  sem_post(&barco_pronto);
  sem_post(&barco_pronto);
}

void atualiza_barco()
{
   int i, id;
   
   barco.y += barco.vel_y;
   barco.x += barco.vel_x;
   for(i=0; i<4;i++)
      if ((id = barco.tripulacao[i]) != -1)
      {
         thrd_status[id].x += barco.vel_x;
         thrd_status[id].y += barco.vel_y;
      }

   if (barco.vel_x == 0)
      return;

   /* se chegou a margem direita */
   if (barco.x >= BARCO_DX)
   {
      barco.x = BARCO_DX;
      barco.vel_x = 0;
      barco_desembarcar();
   }
   else if (barco.x <= BARCO_EX)
   {
      barco.x = BARCO_EX;
      barco.vel_x = 0;
      barco_embarcar();
   }   
}

int atualiza()
{  
   tempo += 0.1f;
   barco.vel_y = 0.25*sinf(tempo);
   atualiza_barco();   
   return 0;
}

void desenha_thrd(int id)
{
   if (thrd_status[id].tipo == HACKER)
   {
      draw_trans_sprite(buffer, imagens.tux, thrd_status[id].x, thrd_status[id].y);
   }
   else
   {
      draw_trans_sprite(buffer, imagens.bill, thrd_status[id].x, thrd_status[id].y);
   }
}

void desenha()
{
   int i;

   set_alpha_blender();
   draw_sprite(buffer, imagens.fundo, 0, 0);
   draw_trans_sprite(buffer, imagens.barco, barco.x, (int)barco.y);

   for (i=0; i<thrd_len; i++)
   {
      desenha_thrd(i);
   }    

   blit(buffer, screen, 0, 0, 0, 0, buffer->w, buffer->h);
   clear_bitmap(buffer);
}

void status_init(int id, e_tipo tipo)
{
   if (id > thrd_len)
   {
      fprintf(stderr, "Thread thrd_id: %d passou ID(%d) fora de fronteira valida.\n", pthread_self(), id);
      exit(1);
   }

   thrd_status[id].thrd_id = pthread_self();
   thrd_status[id].tipo = tipo;
   thrd_status[id].y = (id / NUM_X)*IMG_HEIGHT + START_Y;
   thrd_status[id].x = (id % NUM_X)*IMG_WIDTH + START_X;
}

void barco_add_thrd(int id)
{
   int i;

   for (i=0; i<4; i++)
      if (barco.tripulacao[i] == -1)
      {
         barco.tripulacao[i] = id;
         thrd_status[id].x = barco.x;
         thrd_status[id].y = barco.y;
         
         switch(i)
         {
            case 0:
               thrd_status[id].x += 54;
               thrd_status[id].y += 17;
               break;
            case 1:
               thrd_status[id].x += 100;
               thrd_status[id].y += 25;
               break;
            case 2:
               thrd_status[id].x += 150;
               thrd_status[id].y += 35;
               break;
            case 3:
               thrd_status[id].x += 185;
               thrd_status[id].y += 45;
               break;
         }
         break;
      }
}

void barco_zarpar()
{
   /* se o barco esta na margem esquerda */
   if (barco.x == BARCO_EX)
   {
      pthread_mutex_lock(&mutex_margem);
      barco.vel_x = BARCO_VEL_X;
   }
   else
   {
      barco.vel_x = -BARCO_VEL_X;
      pthread_mutex_unlock(&mutex_margem);
   }

   barco.x += barco.vel_x;
}

void carrega_img()
{
   imagens.tux = load_bitmap("tux.tga", NULL);
   imagens.bill = load_bitmap("bill.tga", NULL);
   imagens.fundo = load_bitmap("fundo.tga", NULL);
   imagens.barco = load_bitmap("barco.tga", NULL);

   if (!imagens.tux || !imagens.bill || !imagens.fundo || !imagens.barco)
   {
      fprintf(stderr, "Erro ao abrir imagens\n");
      exit(2);
   }
}

void libera_img()
{ 
   destroy_bitmap(imagens.tux);
   destroy_bitmap(imagens.bill);
   destroy_bitmap(imagens.fundo);
   destroy_bitmap(imagens.barco);
}

int main(int argn, char** argv)
{
   thrd_len = N*4;
   init_video();
   barco_reset();
   barco.x = BARCO_EX;
   barco.y = BARCO_Y;
   barco.vel_x = 0;
   tempo = 0;
   init_margem();

   pthread_mutex_init(&mutex_margem, NULL);

   if (!initialize()) /* inicializa threads */
   {
      carrega_img();
      /*barco esta pronto para embarcar */
      barco_embarcar();

      while (!key[KEY_ESC])
      {
         atualiza();
         vsync();
         desenha();
      }      

      dispose(); /* libera memoria utilizada nas operacoes multithread */
      destroy_bitmap(buffer);
      libera_img();
      allegro_exit();
   }
   
   pthread_mutex_destroy(&mutex_margem);
   
   return 0;
}
END_OF_MAIN();
